#include "ImageWindow.h"

#include <QWheelEvent>
#include <QMouseEvent>
#include <QResizeEvent>
#include <QTimer>
#include <QPainter>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QDebug>

ImageWindow::ImageWindow(QWidget *parent) :
    QWidget(parent),
    m_fScale(1.0),
    m_bCross(false),
    m_bDynamic(false),
    m_iGrayValue(0),
    m_iCountRButtonUp(0),
    m_bDisableMenu(false),
    m_timerId(0),
    m_bFitToWindow(true),  // 默认启用自适应
    m_dAspectRatio(1.0)    // 默认宽高比
{
    // 初始化Halcon窗口
    m_hWindow.Clear();

    // 创建主布局
    m_mainLayout = new QVBoxLayout(this);
    m_mainLayout->setContentsMargins(0, 0, 0, 0);
    m_mainLayout->setSpacing(0);

    // 创建图片显示控件
    m_picDraw = new QLabel(this);
    m_picDraw->setAlignment(Qt::AlignCenter);
    m_picDraw->setStyleSheet("background-color: black; border: 1px solid gray;");
    m_picDraw->setMinimumSize(400, 300);
    m_picDraw->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    m_picDraw->installEventFilter(this);

    // 创建状态显示标签
    m_statusLabel = new QLabel(this);
    m_statusLabel->setStyleSheet("background-color: #F0F0F0; color: black; padding: 2px; font-family: 微软雅黑; font-size: 9pt;");
    m_statusLabel->setMinimumHeight(20);
    m_statusLabel->setText("就绪");

    // 添加到布局
    m_mainLayout->addWidget(m_picDraw, 1);  // 设置拉伸因子为1
    m_mainLayout->addWidget(m_statusLabel);

    setLayout(m_mainLayout);

    // 设置定时器
    m_timerId = startTimer(2000);

    // 初始化Halcon窗口
    QTimer::singleShot(100, this, &ImageWindow::InitHWindow);
}

ImageWindow::~ImageWindow()
{
    if (m_timerId != 0) {
        killTimer(m_timerId);
    }

    if (m_hWindow.Length() > 0) {
        try {
            HalconCpp::CloseWindow(m_hWindow);
        } catch (...) {
            // 忽略关闭异常
        }
        m_hWindow.Clear();
    }
}

void ImageWindow::InitHWindow()
{
    // 设置控件布局
    if (m_hWindow.Length() > 0) {
        try {
            HalconCpp::CloseWindow(m_hWindow);
        } catch (...) {
            // 忽略关闭异常
        }
        m_hWindow.Clear();
    }

    try {
        // 创建Halcon窗口 - 使用整个QLabel区域
        Hlong windowID = (Hlong)m_picDraw->winId();

        // 获取QLabel的实际可用区域（考虑边距）
        QRect availableRect = m_picDraw->contentsRect();

        OpenWindow(0, 0, availableRect.width(), availableRect.height(),
                   windowID, "visible", "", &m_hWindow);

        // 设置窗口属性
        SetDraw(m_hWindow, "margin");
        SetColored(m_hWindow, 3);
        SetLineWidth(m_hWindow, 2);
        SetSystem("tsp_width", 5000);
        SetSystem("tsp_height", 4000);

        // 如果当前有图像且启用了自适应，则调整显示区域
        if (m_image.IsInitialized() && m_image.CountObj() > 0 && m_bFitToWindow) {
            fitImageToWindow();
        } else {
            // 默认显示区域
            HalconCpp::SetPart(m_hWindow, 0, 0, 1944, 2592);
        }

    } catch (HalconCpp::HException& e) {
        qDebug() << "Halcon窗口初始化失败:" << e.ErrorMessage().Text();
    }
}

void ImageWindow::ClearWindow()
{
    if (m_hWindow.Length() == 0) {
        return;
    }

    try {
        HalconCpp::ClearWindow(m_hWindow);
    } catch (HalconCpp::HException& e) {
        qDebug() << "清空窗口失败:" << e.ErrorMessage().Text();
    }
}

void ImageWindow::ClearObj()
{
    try {
        m_object.Clear();
    } catch (HalconCpp::HException& e) {
        qDebug() << "清空对象失败:" << e.ErrorMessage().Text();
    }
}

void ImageWindow::ClearImage()
{
    try {
        m_image.Clear();
    } catch (HalconCpp::HException& e) {
        qDebug() << "清空图像失败:" << e.ErrorMessage().Text();
    }
}

void ImageWindow::DispImage(HObject image, bool bClearWindow, bool bTrans)
{
    if (m_hWindow.Length() == 0) {
        return;
    }

    try {
        if (bTrans) {
            m_image = image;
        }

        if (bClearWindow) {
            HalconCpp::ClearWindow(m_hWindow);
        }

        if (!image.IsInitialized() || image.CountObj() == 0) {
            return;
        }

        // 如果启用了自适应，调整显示区域
        if (m_bFitToWindow) {
            fitImageToWindow();
        } else {
            HalconCpp::DispObj(image, m_hWindow);
        }

        update();

    } catch (HalconCpp::HException& e) {
        qDebug() << "显示图像失败:" << e.ErrorMessage().Text();
    }
}

void ImageWindow::SetLineWidthX(int iWidth)
{
    if (m_hWindow.Length() == 0) {
        return;
    }

    try {
        SetLineWidth(m_hWindow, iWidth);
    } catch (HalconCpp::HException& e) {
        qDebug() << "设置线宽失败:" << e.ErrorMessage().Text();
    }
}

void ImageWindow::DispObj(HObject obj, const QString& sFormat, bool bClearWindow)
{
    if (m_hWindow.Length() == 0) {
        return;
    }

    try {
        HTuple hColor = HTuple(sFormat.toUtf8().constData());

        if (bClearWindow) {
            HalconCpp::ClearWindow(m_hWindow);
        }

        if (!obj.IsInitialized() || obj.CountObj() == 0) {
            return;
        }

        SetLineWidth(m_hWindow, 2);
        SetColor(m_hWindow, hColor);
        HalconCpp::DispObj(obj, m_hWindow);

    } catch (HalconCpp::HException& e) {
        qDebug() << "显示对象失败:" << e.ErrorMessage().Text();
    }
}

void ImageWindow::SetFont(int Size, const QString& Font, bool bBold, bool bSlant)
{
    if (m_hWindow.Length() == 0) {
        return;
    }

    try {
        HTuple hBold, hSlant;
        bBold ? hBold = "true" : hBold = "false";
        bSlant ? hSlant = "true" : hSlant = "false";

        set_display_font(m_hWindow, Size, HTuple(Font.toUtf8().constData()), hBold, hSlant);

    } catch (HalconCpp::HException& e) {
        qDebug() << "设置字体失败:" << e.ErrorMessage().Text();
    }
}

void ImageWindow::DispText(const QString& sText, const QString& sFormat, int cx, int cy, bool bClearWindow)
{
    if (m_hWindow.Length() == 0) {
        return;
    }

    try {
        if (bClearWindow) {
            HalconCpp::ClearWindow(m_hWindow);
        }

        disp_message(m_hWindow, HTuple(sText.toUtf8().constData()), "image",
                     cy, cx, HTuple(sFormat.toUtf8().constData()), "false");

    } catch (HalconCpp::HException& e) {
        qDebug() << "显示文本失败:" << e.ErrorMessage().Text();
    }
}

void ImageWindow::SetPart(int iLeft, int iTop, int iRight, int iBottom)
{
    if (m_hWindow.Length() == 0) {
        return;
    }

    try {
        HalconCpp::SetPart(m_hWindow, iTop, iLeft, iBottom, iRight);
    } catch (HalconCpp::HException& e) {
        qDebug() << "设置显示区域失败:" << e.ErrorMessage().Text();
    }
}

void ImageWindow::GetWindowImage(HObject &image)
{
    if (m_hWindow.Length() == 0) {
        return;
    }

    try {
        if (!m_image.IsInitialized() || m_image.CountObj() == 0) {
            return;
        }
        image = m_image;
    } catch (...) {
        return;
    }
}

// 事件处理函数
void ImageWindow::wheelEvent(QWheelEvent *event)
{
    if (!m_image.IsInitialized() || m_image.CountObj() == 0 || m_hWindow.Length() == 0) {
        QWidget::wheelEvent(event);
        return;
    }

    // 检查鼠标是否在图片区域内
    if (!m_picDraw->geometry().contains(event->position().toPoint())) {
        QWidget::wheelEvent(event);
        return;
    }

    QPointF scalePt = event->position();
    int zDelta = event->angleDelta().y();
    double scale = 0.1;
    double maxScale = 80.0;

    try {
        HTuple hWidth, hHeight;
        GetImageSize(m_image, &hWidth, &hHeight);
        Hlong width = hWidth[0].I();
        Hlong height = hHeight[0].I();

        // 获取当前显示区域
        HTuple hImageRow0, hImageCol0, hImageRow1, hImageCol1;
        GetPart(m_hWindow, &hImageRow0, &hImageCol0, &hImageRow1, &hImageCol1);

        Hlong imageRow0 = hImageRow0[0].D();
        Hlong imageCol0 = hImageCol0[0].D();
        Hlong imageRow1 = hImageRow1[0].D();
        Hlong imageCol1 = hImageCol1[0].D();

        // 坐标转换
        QPointF imagePt = windowToImage(scalePt.toPoint());

        Hlong newRow0, newCol0, newRow1, newCol1;

        if (zDelta > 0) { // 缩小
            newRow0 = imagePt.y() - 1/(1-scale) * (imagePt.y() - imageRow0);
            newRow1 = imagePt.y() - 1/(1-scale) * (imagePt.y() - imageRow1);
            newCol0 = imagePt.x() - 1/(1-scale) * (imagePt.x() - imageCol0);
            newCol1 = imagePt.x() - 1/(1-scale) * (imagePt.x() - imageCol1);

            if (qAbs(newCol1 - newCol0) / width <= 4) {
                HalconCpp::SetPart(m_hWindow, newRow0, newCol0, newRow1, newCol1);
                m_fScale = width / qAbs(double(newCol1 - newCol0));
            }
        } else { // 放大
            newRow0 = imagePt.y() - 1/(1+scale) * (imagePt.y() - imageRow0);
            newRow1 = imagePt.y() - 1/(1+scale) * (imagePt.y() - imageRow1);
            newCol0 = imagePt.x() - 1/(1+scale) * (imagePt.x() - imageCol0);
            newCol1 = imagePt.x() - 1/(1+scale) * (imagePt.x() - imageCol1);

            if (width / qAbs(double(newCol1 - newCol0)) <= maxScale) {
                HalconCpp::SetPart(m_hWindow, newRow0, newCol0, newRow1, newCol1);
                m_fScale = width / qAbs(double(newCol1 - newCol0));
            }
        }

        // 重新显示
        HalconCpp::SetColored(m_hWindow, 12);
        HalconCpp::ClearWindow(m_hWindow);

        if (m_image.IsInitialized() && m_image.CountObj() > 0) {
            HalconCpp::DispObj(m_image, m_hWindow);
        }

        DisplayCrossCenterLine();
        update();

    } catch (HalconCpp::HException& e) {
        qDebug() << "滚轮事件处理失败:" << e.ErrorMessage().Text();
    }

    QWidget::wheelEvent(event);
}

void ImageWindow::resizeEvent(QResizeEvent *event)
{
    QWidget::resizeEvent(event);

    // 重新初始化Halcon窗口以适应新尺寸
    if (m_hWindow.Length() > 0) {
        try {
            HalconCpp::CloseWindow(m_hWindow);
            m_hWindow.Clear();
        } catch (...) {
            // 忽略异常
        }
    }

    QTimer::singleShot(50, this, &ImageWindow::InitHWindow);
}

void ImageWindow::timerEvent(QTimerEvent *event)
{
    if (event->timerId() == m_timerId) {
        if (m_bDisableMenu) {
            m_bDisableMenu = false;
        }
    }
    QWidget::timerEvent(event);
}

void ImageWindow::mouseMoveEvent(QMouseEvent *event)
{
    if (!m_image.IsInitialized() || m_image.CountObj() == 0 || m_hWindow.Length() == 0) {
        QWidget::mouseMoveEvent(event);
        return;
    }

    QPoint mousePos = event->pos();

    // 检查是否在图片区域内
    if (!m_picDraw->geometry().contains(mousePos)) {
        QWidget::mouseMoveEvent(event);
        return;
    }

    try {
        // 获取当前显示区域
        HTuple hImageRow0, hImageCol0, hImageRow1, hImageCol1;
        GetPart(m_hWindow, &hImageRow0, &hImageCol0, &hImageRow1, &hImageCol1);

        Hlong imageRow0 = hImageRow0[0].D();
        Hlong imageCol0 = hImageCol0[0].D();
        Hlong imageRow1 = hImageRow1[0].D();
        Hlong imageCol1 = hImageCol1[0].D();

        // 坐标转换
        QPointF imagePt = windowToImage(mousePos);

        HTuple x = imagePt.x();
        HTuple y = imagePt.y();
        x = x.TupleRound();
        y = y.TupleRound();

        // 获取图像信息
        HTuple hWidth, hHeight;
        GetImageSize(m_image, &hWidth, &hHeight);
        Hlong iWidth = hWidth[0].I();
        Hlong iHeight = hHeight[0].I();

        if (x[0].I() >= 0 && x[0].I() < iWidth && y[0].I() >= 0 && y[0].I() < iHeight) {
            QString statusText;

            HTuple hChannels;
            CountChannels(m_image, &hChannels);

            if (hChannels.Length() > 0 && hChannels[0].I() == 3) {
                HObject hImageRed, hImageGreen, hImageBlue;
                Decompose3(m_image, &hImageRed, &hImageGreen, &hImageBlue);

                HTuple gray1, gray2, gray3;
                GetGrayval(hImageRed, y, x, &gray1);
                GetGrayval(hImageGreen, y, x, &gray2);
                GetGrayval(hImageBlue, y, x, &gray3);

                statusText = QString("x=%1, y=%2, RGB=(%3, %4, %5), 缩放: %6")
                                 .arg(x[0].I()).arg(y[0].I())
                                 .arg(gray1[0].I()).arg(gray2[0].I()).arg(gray3[0].I())
                                 .arg(m_fScale, 0, 'f', 2);
            } else if (hChannels.Length() > 0 && hChannels[0].I() == 1) {
                HTuple gray;
                GetGrayval(m_image, y, x, &gray);

                statusText = QString("x=%1, y=%2, 灰度=%3, 缩放: %4")
                                 .arg(x[0].I()).arg(y[0].I())
                                 .arg(gray[0].D(), 0, 'f', 3).arg(m_fScale, 0, 'f', 2);
            } else {
                statusText = QString("x=%1, y=%2, 缩放: %3")
                                 .arg(x[0].I()).arg(y[0].I()).arg(m_fScale, 0, 'f', 2);
            }

            updateStatusDisplay(statusText);
        }

    } catch (HalconCpp::HException& e) {
        qDebug() << "鼠标移动事件处理失败:" << e.ErrorMessage().Text();
    }

    QWidget::mouseMoveEvent(event);
}

void ImageWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::RightButton && !m_bDisableMenu) {
        m_iCountRButtonUp++;

        if (m_iCountRButtonUp == 2) {
            m_iCountRButtonUp = 0;
        }

        if (m_iCountRButtonUp == 1) {
            // 这里可以添加上下文菜单
            // QMenu contextMenu;
            // ... 添加菜单项
            // contextMenu.exec(event->globalPos());
        }
    }

    QWidget::mouseReleaseEvent(event);
}

bool ImageWindow::eventFilter(QObject *obj, QEvent *event)
{
    if (obj == m_picDraw) {
        if (event->type() == QEvent::Paint) {
            // 可以在这里添加自定义绘制
        }
    }
    return QWidget::eventFilter(obj, event);
}

void ImageWindow::paintEvent(QPaintEvent *event)
{
    QWidget::paintEvent(event);
}

void ImageWindow::onTimerTimeout()
{
    if (m_bDisableMenu) {
        m_bDisableMenu = false;
    }
}

void ImageWindow::fitImageToWindow()
{
    if (m_hWindow.Length() == 0 || !m_image.IsInitialized() || m_image.CountObj() == 0) {
        return;
    }

    try {
        HTuple hWidth, hHeight;
        GetImageSize(m_image, &hWidth, &hHeight);
        Hlong width = hWidth[0].I();
        Hlong height = hHeight[0].I();

        // 计算宽高比
        m_dAspectRatio = (double)width / height;

        // 获取窗口可用区域
        QRect availableRect = m_picDraw->contentsRect();
        double windowAspect = (double)availableRect.width() / availableRect.height();

        Hlong displayWidth, displayHeight;

        if (m_dAspectRatio > windowAspect) {
            // 图像比窗口宽，以宽度为基准
            displayWidth = width;
            displayHeight = (Hlong)(width / windowAspect);
        } else {
            // 图像比窗口高，以高度为基准
            displayHeight = height;
            displayWidth = (Hlong)(height * windowAspect);
        }

        // 计算居中显示的区域
        Hlong row0 = (height - displayHeight) / 2;
        Hlong col0 = (width - displayWidth) / 2;
        Hlong row1 = row0 + displayHeight;
        Hlong col1 = col0 + displayWidth;

        // 设置显示区域
        HalconCpp::SetPart(m_hWindow, row0, col0, row1, col1);
        m_fScale = (double)width / (col1 - col0);

        // 重新显示图像
        updateImageDisplay();

    } catch (HalconCpp::HException& e) {
        qDebug() << "自适应显示失败:" << e.ErrorMessage().Text();
    }
}

void ImageWindow::updateImageDisplay()
{
    if (m_hWindow.Length() == 0) {
        return;
    }

    try {
        HalconCpp::ClearWindow(m_hWindow);

        if (m_image.IsInitialized() && m_image.CountObj() > 0) {
            HalconCpp::DispObj(m_image, m_hWindow);
        }

        DisplayCrossCenterLine();
        update();

    } catch (HalconCpp::HException& e) {
        qDebug() << "更新图像显示失败:" << e.ErrorMessage().Text();
    }
}

// 工具函数实现
QPointF ImageWindow::windowToImage(const QPoint& windowPoint)
{
    if (m_hWindow.Length() == 0) return QPointF();

    try {
        HTuple hImageRow0, hImageCol0, hImageRow1, hImageCol1;
        GetPart(m_hWindow, &hImageRow0, &hImageCol0, &hImageRow1, &hImageCol1);

        Hlong imageRow0 = hImageRow0[0].D();
        Hlong imageCol0 = hImageCol0[0].D();
        Hlong imageRow1 = hImageRow1[0].D();
        Hlong imageCol1 = hImageCol1[0].D();

        QRect picRect = m_picDraw->geometry();

        double x = 1.0 * (windowPoint.x() - picRect.left()) *
                       (1.0 * (imageCol1 - imageCol0) / picRect.width()) + imageCol0;
        double y = 1.0 * (windowPoint.y() - picRect.top()) *
                       (1.0 * (imageRow1 - imageRow0) / picRect.height()) + imageRow0;

        return QPointF(x, y);

    } catch (HalconCpp::HException& e) {
        return QPointF();
    }
}

void ImageWindow::updateStatusDisplay(const QString& text)
{
    m_statusLabel->setText(text);
}

void ImageWindow::DisplayCrossCenterLine()
{
    if (m_hWindow.Length() == 0 || !m_image.IsInitialized() || m_image.CountObj() == 0 || !m_bCross) {
        return;
    }

    try {
        HTuple hWidth, hHeight;
        GetImageSize(m_image, &hWidth, &hHeight);
        Hlong iWidth = hWidth[0].I();
        Hlong iHeight = hHeight[0].I();

        // 显示十字线
        SetColor(m_hWindow, "red");
        SetLineWidth(m_hWindow, 2);

        DispLine(m_hWindow, iHeight/2, 0, iHeight/2, iWidth);
        DispLine(m_hWindow, 0, iWidth/2, iHeight, iWidth/2);

        SetLineWidth(m_hWindow, 2);

    } catch (HalconCpp::HException& e) {
        qDebug() << "显示十字线失败:" << e.ErrorMessage().Text();
    }
}


// Halcon工具函数 (保持原样，只需要修改函数名为成员函数)
void ImageWindow::disp_message(HTuple hv_WindowHandle, HTuple hv_String, HTuple hv_CoordSystem,
                               HTuple hv_Row, HTuple hv_Column, HTuple hv_Color, HTuple hv_Box)
{
    // Local iconic variables

    // Local control variables
    HTuple  hv_GenParamName, hv_GenParamValue;
    //Convert the parameters for disp_text.
    if (0 != (HTuple(int(hv_Row == HTuple())).TupleOr(int(hv_Column == HTuple()))))
    {
        return;
    }
    if (0 != (int(hv_Row == -1)))
    {
        hv_Row = 12;
    }
    if (0 != (int(hv_Column == -1)))
    {
        hv_Column = 12;
    }
    //
    //Convert the parameter Box to generic parameters.
    hv_GenParamName = HTuple();
    hv_GenParamValue = HTuple();
    if (0 != (int((hv_Box.TupleLength()) > 0)))
    {
        if (0 != (int(HTuple(hv_Box[0]) == HTuple("false"))))
        {
            //Display no box
            hv_GenParamName = hv_GenParamName.TupleConcat("box");
            hv_GenParamValue = hv_GenParamValue.TupleConcat("false");
        }
        else if (0 != (int(HTuple(hv_Box[0]) != HTuple("true"))))
        {
            //Set a color other than the default.
            hv_GenParamName = hv_GenParamName.TupleConcat("box_color");
            hv_GenParamValue = hv_GenParamValue.TupleConcat(HTuple(hv_Box[0]));
        }
    }
    if (0 != (int((hv_Box.TupleLength()) > 1)))
    {
        if (0 != (int(HTuple(hv_Box[1]) == HTuple("false"))))
        {
            //Display no shadow.
            hv_GenParamName = hv_GenParamName.TupleConcat("shadow");
            hv_GenParamValue = hv_GenParamValue.TupleConcat("false");
        }
        else if (0 != (int(HTuple(hv_Box[1]) != HTuple("true"))))
        {
            //Set a shadow color other than the default.
            hv_GenParamName = hv_GenParamName.TupleConcat("shadow_color");
            hv_GenParamValue = hv_GenParamValue.TupleConcat(HTuple(hv_Box[1]));
        }
    }
    //Restore default CoordSystem behavior.
    if (0 != (int(hv_CoordSystem != HTuple("window"))))
    {
        hv_CoordSystem = "image";
    }
    //
    if (0 != (int(hv_Color == HTuple(""))))
    {
        //disp_text does not accept an empty string for Color.
        hv_Color = HTuple();
    }
    //
    HalconCpp::DispText(hv_WindowHandle, hv_String, hv_CoordSystem, hv_Row, hv_Column, hv_Color,
                        hv_GenParamName, hv_GenParamValue);
    return;
}

void ImageWindow::set_display_font(HTuple hv_WindowHandle, HTuple hv_Size, HTuple hv_Font,
                                   HTuple hv_Bold, HTuple hv_Slant)
{

    // Local iconic variables

    // Local control variables
    HTuple  hv_OS, hv_Fonts, hv_Style, hv_Exception;
    HTuple  hv_AvailableFonts, hv_Fdx, hv_Indices;

    //This procedure sets the text font of the current window with
    //the specified attributes.
    //
    //Input parameters:
    //WindowHandle: The graphics window for which the font will be set
    //Size: The font size. If Size=-1, the default of 16 is used.
    //Bold: If set to 'true', a bold font is used
    //Slant: If set to 'true', a slanted font is used
    //
    GetSystem("operating_system", &hv_OS);
    if (0 != (HTuple(int(hv_Size == HTuple())).TupleOr(int(hv_Size == -1))))
    {
        hv_Size = 16;
    }
    if (0 != (int((hv_OS.TupleSubstr(0, 2)) == HTuple("Win"))))
    {
        //Restore previous behaviour
        hv_Size = (1.13677*hv_Size).TupleInt();
    }
    else
    {
        hv_Size = hv_Size.TupleInt();
    }
    if (0 != (int(hv_Font == HTuple("Courier"))))
    {
        hv_Fonts.Clear();
        hv_Fonts[0] = "Courier";
        hv_Fonts[1] = "Courier 10 Pitch";
        hv_Fonts[2] = "Courier New";
        hv_Fonts[3] = "CourierNew";
        hv_Fonts[4] = "Liberation Mono";
    }
    else if (0 != (int(hv_Font == HTuple("mono"))))
    {
        hv_Fonts.Clear();
        hv_Fonts[0] = "Consolas";
        hv_Fonts[1] = "Menlo";
        hv_Fonts[2] = "Courier";
        hv_Fonts[3] = "Courier 10 Pitch";
        hv_Fonts[4] = "FreeMono";
        hv_Fonts[5] = "Liberation Mono";
    }
    else if (0 != (int(hv_Font == HTuple("sans"))))
    {
        hv_Fonts.Clear();
        hv_Fonts[0] = "Luxi Sans";
        hv_Fonts[1] = "DejaVu Sans";
        hv_Fonts[2] = "FreeSans";
        hv_Fonts[3] = "Arial";
        hv_Fonts[4] = "Liberation Sans";
    }
    else if (0 != (int(hv_Font == HTuple("serif"))))
    {
        hv_Fonts.Clear();
        hv_Fonts[0] = "Times New Roman";
        hv_Fonts[1] = "Luxi Serif";
        hv_Fonts[2] = "DejaVu Serif";
        hv_Fonts[3] = "FreeSerif";
        hv_Fonts[4] = "Utopia";
        hv_Fonts[5] = "Liberation Serif";
    }
    else
    {
        hv_Fonts = hv_Font;
    }
    hv_Style = "";
    if (0 != (int(hv_Bold == HTuple("true"))))
    {
        hv_Style += HTuple("Bold");
    }
    else if (0 != (int(hv_Bold != HTuple("false"))))
    {
        hv_Exception = "Wrong value of control parameter Bold";
        throw HException(hv_Exception);
    }
    if (0 != (int(hv_Slant == HTuple("true"))))
    {
        hv_Style += HTuple("Italic");
    }
    else if (0 != (int(hv_Slant != HTuple("false"))))
    {
        hv_Exception = "Wrong value of control parameter Slant";
        throw HException(hv_Exception);
    }
    if (0 != (int(hv_Style == HTuple(""))))
    {
        hv_Style = "Normal";
    }
    QueryFont(hv_WindowHandle, &hv_AvailableFonts);
    hv_Font = "";
    {
        HTuple end_val48 = (hv_Fonts.TupleLength()) - 1;
        HTuple step_val48 = 1;
        for (hv_Fdx = 0; hv_Fdx.Continue(end_val48, step_val48); hv_Fdx += step_val48)
        {
            hv_Indices = hv_AvailableFonts.TupleFind(HTuple(hv_Fonts[hv_Fdx]));
            if (0 != (int((hv_Indices.TupleLength())>0)))
            {
                if (0 != (int(HTuple(hv_Indices[0]) >= 0)))
                {
                    hv_Font = HTuple(hv_Fonts[hv_Fdx]);
                    break;
                }
            }
        }
    }
    if (0 != (int(hv_Font == HTuple(""))))
    {
        throw HException("Wrong value of control parameter Font");
    }
    hv_Font = (((hv_Font + "-") + hv_Style) + "-") + hv_Size;
    HalconCpp::SetFont(hv_WindowHandle, hv_Font);
    return;
}

void ImageWindow::gen_arrow_contour_xld(HObject *Arrow, HTuple Row1, HTuple Column1,
                                        HTuple Row2, HTuple Column2, HTuple HeadLength, HTuple HeadWidth)
{
    using namespace HalconCpp;

    // Local iconic variables
    HObject  TempArrow;


    // Local control variables
    HTuple  Length, ZeroLengthIndices, DR, DC, HalfHeadWidth;
    HTuple  RowP1, ColP1, RowP2, ColP2, Index;

    //This procedure generates arrow shaped XLD contours,
    //pointing from (Row1, Column1) to (Row2, Column2).
    //If starting and end point are identical, a contour consisting
    //of a single point is returned.
    //
    //input parameteres:
    //Row1, Column1: Coordinates of the arrows' starting points
    //Row2, Column2: Coordinates of the arrows' end points
    //HeadLength, HeadWidth: Size of the arrow heads in pixels
    //
    //output parameter:
    //Arrow: The resulting XLD contour
    //
    //The input tuples Row1, Column1, Row2, and Column2 have to be of
    //the same length.
    //HeadLength and HeadWidth either have to be of the same length as
    //Row1, Column1, Row2, and Column2 or have to be a single element.
    //If one of the above restrictions is violated, an error will occur.
    //
    //
    //Init
    GenEmptyObj(&(*Arrow));
    //
    //Calculate the arrow length
    DistancePp(Row1, Column1, Row2, Column2, &Length);
    //
    //Mark arrows with identical start and end point
    //(set Length to -1 to avoid division-by-zero exception)
    ZeroLengthIndices = Length.TupleFind(0);
    if (0 != (ZeroLengthIndices!=-1))
    {
        Length[ZeroLengthIndices] = -1;
    }
    //
    //Calculate auxiliary variables.
    DR = (1.0*(Row2-Row1))/Length;
    DC = (1.0*(Column2-Column1))/Length;
    HalfHeadWidth = HeadWidth/2.0;
    //
    //Calculate end points of the arrow head.
    RowP1 = (Row1+((Length-HeadLength)*DR))+(HalfHeadWidth*DC);
    ColP1 = (Column1+((Length-HeadLength)*DC))-(HalfHeadWidth*DR);
    RowP2 = (Row1+((Length-HeadLength)*DR))-(HalfHeadWidth*DC);
    ColP2 = (Column1+((Length-HeadLength)*DC))+(HalfHeadWidth*DR);
    //
    //Finally create output XLD contour for each input point pair
    for (Index=0; Index<=(Length.Length())-1; Index+=1)
    {
        if (0 != (HTuple(Length[Index])==-1))
        {
            //Create_ single points for arrows with identical start and end point
            GenContourPolygonXld(&TempArrow, HTuple(Row1[Index]), HTuple(Column1[Index]));
        }
        else
        {
            //Create arrow contour
            GenContourPolygonXld(&TempArrow, ((((HTuple(Row1[Index]).TupleConcat(HTuple(Row2[Index]))).TupleConcat(HTuple(RowP1[Index]))).TupleConcat(HTuple(Row2[Index]))).TupleConcat(HTuple(RowP2[Index]))).TupleConcat(HTuple(Row2[Index])),
                                 ((((HTuple(Column1[Index]).TupleConcat(HTuple(Column2[Index]))).TupleConcat(HTuple(ColP1[Index]))).TupleConcat(HTuple(Column2[Index]))).TupleConcat(HTuple(ColP2[Index]))).TupleConcat(HTuple(Column2[Index])));
        }
        ConcatObj((*Arrow), TempArrow, &(*Arrow));
    }
    return;
}
